����������������������������������������������������������������������������������������������
�                                                                                            �
�                              [x] ringZ3r0  Proudly Presents [x]                            �
�                                                                                            �
�                 ������������������������������������������������������������               �
�                                                                                            �
                  � PE-Crypters : uno sguardo da vicino al c.d. "formato" PE �

                                            Kill3xx

                                         02 Marzo,1999


SORGENTI

--==[  PREMESSA  ]==--------------------------------------------------------------------------

LE INFORMAZIONI CHE TROVATE ALL'INTERNO DI QUESTO FILE SONO PER PURO SCOPO DIDATTICO.
L'AUTORE NON INCORAGGIA CHI VOLESSE UTILIZZARLE PER SCOPI ILLEGALI.

--==[ DIFFICOLTA' ]==-------------------------------------------------------------------------

scala : *=Novizio, **=Apprendista, ***=Esperto, ****=Guru
target: ***

--==[ TOOLS USATI ]==-------------------------------------------------------------------------

* TASM
* PROCDUMP 1.3
* PE Browse
* HIEW 6.01  

--==[ LETTERATURA ]==-------------------------------------------------------------------------

"Peering Inside the PE: A Tour of the Win32 Portable Executable File Format" (M. Pietrek), 
 Microsoft Systems Journal 3/1994

"Windows 95 Programming Secrets" (M. Pietrek), IDG BOOKS, 1995

"Why to Use _declspec(dllimport) & _declspec(dllexport) In Code", MS KB Q132044

"Writing Multiple-Language Resources", MS Knowledge Base Q89866

"The Portable Executable File Format from Top to Bottom" (Randy Kath), MSDN

"The PE file format" (B. Luevelsmeyer), reperibile sulla rete

--==[ INTRODUZIONE ]==------------------------------------------------------------------------
Salve gente :)
Quello che vi presento questa volta e' il primo di una serie di tre tutorial sul formato PE 
e soprattutto sull'utilizzo/abuso che ne fanno i vari PE-Crypters/Packers/Wrappers.
Come avete sicuramente notato negli ultimi tempi c'e' stata un'esplosione di crypters e
packers freeware/share/commerciali e sopratutto un loro massiccio impiego come parte della 
protezione di un programma: questo si spiega con il fatto che il formato PE e' oramai piu' 
o meno conosciuto e che soprattutto e' noto come il loader di win95/Nt crea un processo a 
partire dall'immagine su disco (qui dobbiamo ringraziare i vari Pietrek,Shulman,ecc. per aver
aperto il vaso di Pandora;)
Nel primo (quello che state leggendo :)) trattero' del formato PE in generale e cerchero' di
commentare i sorgenti di un semplice pe-crypter da me scritto per l'occasione. Nel secondo
parleremo di unpacking "a mano" o assistito :) (Procdump,SoftDump,ecc.), ed infine nel terzo
se tutto filera' liscio vedremo come realizzare un decrypter e alcune tecninche anti-dumping.
Una premessa: nell'analizzare questo formato non mi dilungero' su quali siano le origini di
questo formato o su il significato di tutte le strutture e/o campi che lo compongono:
in primo luogo perche' potete trovare dettagliate informazioni nei testi riportati nella
"letteratua", in secondo luogo perche' molte di queste strutture/campi o non sono coerenti 
fra i vari linker o sono obsolete, o semplicemente non sono fondamentali per i nostri scopi
(ricordate che parliamo di pe-crypters).

--==[ IL FORMATO PORTABLE EXECUTABLE ]==------------------------------------------------------

Per una visione di insieme del formato PE dobbiamo far ricorso alla fonte princiapale di
documentazione (l'unica prima dei testi di Pietrek e Kath):
 winnt.h
Questo ominipresente file header (fornito con tutti gli SDK,DDK di M$) contiene la definizione
delle principali strutture e costanti che interessano il formato PE, quindi per qualsiasi cosa
dovremmo fare riferimento a questo file. La principale caratteristica di questo formato e' la
relativa facilita' con cui il loader puo' reperire le informazioni con cui "creare" un nuovo
processo, che si traduce poi in una maggior velocita' di caricamento/esecuzione di una
applicazione/modulo, e chi ha presente il formato NE sa cosa voglio dire!
Il layout di un exe PE e' tendenzialmente (si esatto proprio "tendenzialmente") questo:

    +===================+  +00 -> dos header.[3C] ---+
    | DOS (MZ) Header   |                            |
    +-------------------+  +40                       |
    | DOS Stub          |                            |
    +===================+  +00 -> inizio PE header <-+
    | NT (PE) Header    |
    |- - - - - - - - - -|  +04
    | file-header       |
    |- - - - - - - - - -|  +1A
    | optional header   |
    |- - - - - - - - - -|  +78
    | data directories  |
    |                   |
    +===================+  <- PE header + FileHeader.SizeOfOptionalHeader +
sizeOf(FileHeader)
    | section headers   |
    |       array       |
    ~-------------------~
    |......padding......|
    ~-------------------~
    |                   |
    | dati section2     |
    |                   |
    +-------------------+
    |                   |
    | dati section2     |
    |                   |
    +-------------------+
    | ..............    |
    +-------------------+
    |                   |
    | dati section n    |
    |                   |
    +-------------------+

Come vedete la prima struttura che incontriamo e' il DosHeader (buon vecchio dos ;)):

IMAGE_DOS_HEADER STRUC
    e_magic                   DW      ?   ;+00     ; Magic number
    ......
    e_lfanew                  DD      ?   ;+3C     ; Address of PE header
IMAGE_DOS_HEADER  ENDS

Di questa struttura cio' che maggiormente ci interessa sono
e_magic : questa DW contiene la signature che identifica un file eseguibile DOS valido ed
          e' definita come : 0x05A4 che corrisponde alla stringa MZ (no dai!?? ;))
e_lfanew: questa DD invece e' invece la chiave di accesso alla nuovo header PE.
          Si tratta di un RVA (ne parliamo dopo degli RVA) che punta all'inizio della
          struttura NT Headers. Di conseguenza se volete ad exp. ottenere l'offset del
          PE Header relativo all'inizio di file mappato in memoria dovrete prima leggere
          questo valore e quindi sommarlo alla base del vista del Memory Mapped File
          (da ora MMF per gli amici ;)
La presenza del campo e_lfanew si spiega con il fatto che di seguito al Dos Header possiamo
trovare uno stub ms-dos: questo altro non e' che quel mini-programma ci avverte
cordialmente :)) che l'eseguibile e' destinato all'ambiente Win32,OS/2, ecc.. Dato che questo
stub e' _opzionale_ si e' reso necessario fornire un pratico sistema al loader per evitare
di impaltanarsi nel caso lo stub non fosse linkato o di dimensioni diverse.
       
Ora guardiamo piu' in dettaglio la struttura IMAGE_NT_HEADERS:

    31                         0 31                         0
    +-------------------------------------------------------+ <--+
    |          SIGNATURE        |   MACHINE   | # SECTIONS  |    |
    +---------------------------+-------------+-------------+    | Signature  +
    |       TIME/DATE STAMP     |  POINTER TO SYMBOL TABLE  |    | FileHeader
    +---------------------------+-------------+-------------+    |
    |    NUMBER OF SYMBOL       |  NT HDR SIZE| IMAGE FLAGS | <--+
    +=============+======+======+=============+=============+ <--+
    |    MAGIC    |LMAJOR|LMINOR|       SIZE OF CODE        "|.class" tppabs="http://www.crackstore.com/tutorz/%7c.class"    |
    +-------------+------+------+---------------------------+    |
    | SIZE OF INITIALIZED DATA  | SIZE OF UNINITIALIZED DATA|    |
    +---------------------------+---------------------------+    |
    |       ENTRYPOINT RVA      |        BASE OF CODE       |    |
    +---------------------------+---------------------------+    |
    |        BASE OF DATA       |        IMAGE BASE         |    |
    +---------------------------+---------------------------+    |
    |    SECTION ALIGNMENT      |      FILE ALIGNMENT       |    |
    +-------------+-------------+-------------+-------------+    | Optional Header
    |  OS MAJOR   |  OS MINOR   |  USER MAJOR |  USER MINOR |    |
    +-------------+-------------+-------------+-------------+    |
    | SUBSYS MAJOR| SUBSYS MINOR|       WIN32 VERSION       |    |
    +-------------+-------------+---------------------------+    |
    |        IMAGE SIZE         |       HEADER SIZE         |    |
    +---------------------------+-------------+-------------+    |
    |       FILE CHECKSUM       |  SUBSYSTEM  |  DLL FLAGS  |    |
    +---------------------------+-------------+-------------+    |
    |   STACK RESERVE SIZE      |     STACK COMMIT SIZE     |    |
    +---------------------------+---------------------------+    |
    |   HEAP RESERVE SIZE       |     HEAP COMMIT SIZE      |    |
    +---------------------------+---------------------------+    |
    |       LOADER FLAGS        |  # INTERESTING RVA/SIZES  |    |
    +===========================+===========================+    | <-+
    |   EXPORT TABLE RVA        |   TOTAL EXPORT DATA SIZE  |    |   |
    +---------------------------+---------------------------+    |   |
    |   IMPORT TABLE RVA        |   TOTAL IMPORT DATA SIZE  |    |   |
    +---------------------------+---------------------------+    |   |
    |  RESOURCE TABLE RVA       |  TOTAL RESOURCE DATA SIZE |    |   |
    +---------------------------+---------------------------+    |   |
    |  EXCEPTION TABLE RVA      | TOTAL EXCEPTION DATA SIZE |    |   |
    +---------------------------+---------------------------+    |   |
    |  SECURITY TABLE RVA       |  TOTAL SECURITY DATA SIZE |    |   |  Data Directory
    +---------------------------+---------------------------+    |   |
    |    FIXUP TABLE RVA        |   TOTAL FIXUP DATA SIZE   |    |   |
    +---------------------------+---------------------------+    |   |
    |    DEBUG TABLE RVA        |  TOTAL DEBUG DIRECTORIES  |    |   |
    +---------------------------+---------------------------+    |   |
    |  IMAGE DESCRIPTION RVA    |  TOTAL DESCRIPTION SIZE   |    |   |
    +---------------------------+---------------------------+    |   |
    |   MACHINE SPECIFIC RVA    |   MACHINE SPECIFIC SIZE   |    |   |
    +---------------------------+---------------------------+    |   |
    |  THREAD LOCAL STORAGE RVA |      TOTAL TLS SIZE       |    |   |
    +---------------------------+---------------------------+    |   |
    |  LOADER CONFIGURATION RVA |     LOADER DATA SIZE      |    |   |
    +---------------------------+---------------------------+    |   |
    |   BOUNDED IMPORTS TABLE   | BOUNDED IMPORTS DATA SIZE |    |   |
    +---------------------------+---------------------------+    |   |
    |  IMPORT ADDRESSES TABLE   |       TOTAL IAT SIZE      |    |   |
    +---------------------------+---------------------------+ <--+ <-+


come vedete e' l'unione di due strutture , l'IMAGE_FILE_HEADER e IMAGE_OPTIONAL_HEADER,
piu' una DWORD, la c.d. signature: questo ci porta ad una prima considerazione ovvero
che gli headers del PE sono _CONSECUTIVI_ in memoria (o su disco) e quindi i campi possono
essere letti con semplicita' come offsets relativi all'inizio degli NT headers.
Ora analizziamo i campi piu' importatanti (per questioni di spazio non riporto la
dichiarazione degli headers, plz fate riferimento al file imghdr.inc)

* Signature : questo signature ha la funzione di identificare il tipo di eseguibile e il S.O.
           (o sottosistema per NT) a cui e' destinato l'eseguibile; ad esempio :
            IMAGE_OS2_SIGNATURE       0x0454E     = NE   = new executable = os/2 o win3x
            IMAGE_NT_SIGNATURE        0x000004550 = PE00 = win9x / winNT

#IMAGE_FILE_HEADER#

* Machine: indica il processore target (ricordate che NT e' multiplatform)         
* TimeDateStamp: time stamp usata per identificare la versione del modulo (ad esempio
           nel meccanismo di import binding), ma spesso inconsistente. Non fidatevi!
* NumberOfSections: indica il numero di sezioni presenti, nonche' il numero di entries
           nel section headers table. In teoria dovrebbe essere consistente con il numero
           di sezioni presenti ma non fidatevi visto che il loader non pare curarsene.
* ImgFlags: indica il tipo di immagine (ad esempio eseguibile,dll) ed alcune caratteristiche
           che la riguardano e che sono derivate dalla opzioni di compilazione/linking
           (ad esempio se sono presenti le informazioni di debug,numeri di linea,ecc.
           se e' stata impostata una imagebase fixed,ecc.
*SizeOfOptionalHeaders: indica la size degli optional headers (normamente 0xE0). La presenza
           di questo campo e' la conseguenza della natura estensibile del formato PE.
        
#IMAGE_OPTIONAL_HEADER#
        
Questa struttura e' diciamo la piu' importante, in quanto raccoglie molte delle informazioni
vitali che verranno utilizzate dal loader per recuperare i dati dalle sezioni e quindi creare
il process in memoria. Anche in questo caso analizzeremo le piu' importanti in quanto come
vi ho gia' anticipato gli altri campi non appaiono essere consistenti da linker a linker o
tra versioni diverse di questi, o addirittura ignorati (rientrano in questa categoria anche
i vari SizeOfCode,SizeOfInitializedData,SizeOfUnitializedData):

* AddressOfEntryPoint: questo campo contine l'RVA dell'entrypoint del modulo, cioe' il punto
           in cui il loader trasferira' l'esecuzione una volta terminata la fase di
           caricamento/ inizializzaione: inevitabilmente punta all'interno di una sezione 
           che possiede i flag readable/executable (solitamente .text, CODE)
* BaseOfCode: indica l'RVA della prima sezione di codice (.text, CODE) ed utilizzata
           presumibilmene dal loader nella fase di mapping per settare gli attributi di pagina
* BaseOfData: idem come sopra ma per la prima sezione dati
* ImageBase: questo campo e' di vitale importanza in quanto riporta la cosidetta "preferred
           imagebase" ovvero l'indirizzo lineare nello spazio di indirizzamento privato
           utilizzato dal linker per risolvere gran parte dei fixup nonche' la base a cui si
           riferiscono tutti gli RVA: questo significa che se il loader di windowz deve
           mappare l'immagine ad un indirizzo diverso sara' necessario applicare le base 
           relocations (parlero piu' in dettaglio delle implicazini della imagebase nella 
           sezione RVA e base rilocations).
* SectionAlignment: quando il loader di window mappa in memoria il file immagine utilizza i
           MMF in modo che occupi uno blocco consecutivo di memoria nello spazio di
           indirizzamento.Tuttavia per questioni di ottimizzazione nella gestione della 
           memoria virtuale (ad exp. nello share di porzioni di codice, nel caricamento di 
           pagine non presenti,ecc.) in w9x ogni sezione deve essere allineata ad un multiplo 
           della unita' minima gestita dal VMM : 1 pagina x86 = 4096 = 1000h (attenzione a non
           confonderla con la granularita' di allocazione che e' di 64k). Questa limitazione 
           non si applica a NT (il minimo e' 32byte) ma non credo che vogliate degli eseguibili
           "incompatibili".
* FileAlignment: questo campo e' un antico retaggio di quando windowz95 utilizzava il
           filesystem FAT, e per ottimizzare i caricamenti si era pensato di allineare i dati 
           delle sezioni su disco ad un multiplo della grandezza di un settore (200h = 512 b).
           Nel caso sia necessario i linkers zero-paddano (azz che espessione :) lo spazio non
           utilizzato.
* SizeOfImage: ecco un esempio di come i membri della famiglia Win32 non comunichino molto!:)
           questo campo riporta la grandezza dell'immagine una volta  in memoria e quindi lo
           spazio totale che il loader deve riservare per il suo caricamento. E' costituita
           dalla somma dell'header + le VirtualSize delle sezioni presenti ed arrotondata
           al multiplo piu' vicino della SectionAlignment. Quest'ultimo fatto e' stato fonte
           di problemi per molti coders che avevano testato le loro creature solo con win95 
           dato che questo ignora l'allineamento continuando pacificamente mentre NT si 
           inkazza non poko se non trova un valore consistente. 
           Mi raccomando non fate inkazzare NT ;)
* SizeOfHeaders: il valore qui riportato altro non e' che la somma delle dimensioni dei vari
           headers che precedono i dati delle sections
(DosHeader+Stub+NtHeaders,SectionHeaders):
           in sostanza e' una sorta di puntatore ai rawdata dato che ImageBase+SizeOfHeaders
           vi porta direttamente all'inizio della prima sezione, sia che stiate lavorando con
           l'immagine di un processo in memoria,o su disco/MMF.
* CheckSum: altro esempio di differente comportamento fra 9x/Nt: questo valore rappresenta un
           checksum dell'immagine del file PE, concepita per evitare che il loader carichi un
           eseguibile corrotto e/o inconsistente, solo che questa verifica e' effettivamente
           compiuta solo dal loader di NT e esclusivamente per file di sistema. Win9x ignora
           totalmente questo campo tant'e' che i linker normalmente lasciano a 0 questo
           campo. Nel caso vogliate modificare un PE che sapete essere di utilizzato da Nt a 
           livello di sistema (ad exp. un service, una dll, ecc.) e' auspicabile che aggorniate
           correttamente il campo. L'algoritmo di calcolo e' ofcoz propietario M$ ma cmq
           e' possibile utilizzare la funzione CheckSumMappedFile esportata dalla ImgHlp.dll
           ormai molto in voga sui sistemi M$;)
* NumberOfRvaAndSizes: questo campo indica la dimensione dell'array di strutture
           IMAGE_DATA_DIRECTORY che inizia dal campo DataDirectory. Attualmente e' fissato a
           16 elementi ma non necessariamente per sempre ;)
* DataDirectory: questo pseudocampo in realta e' un array di strutture che rappresentano per
           il loader una sorta di shortcut per accedere velocemente alle informazioni piu'
           sensibili per la creazione/inizializzazione del processo: ogni entry (indici da
           0..15) riporta l'RVA e la VirtualSize di specifiche informazioni/strutture:
           le piu' importati sono:
           0 : funzioni esportate dal modulo (ET)
           1 : funzioni importate ma non bounded (IT)
           2 : inizio della resource directory (resROOT)
           5 : base relocations
           9 : blocco thread local storage (TLS)
           11: funzioni importate bound (BIT)
           12: import addresse table (IAT)
           Una cosa importante da dire e' che il loader fa sempre riferimento a questa
           tabella per accedere ai dati del processo e non alla tabella dei section headers.
           Se volete ad exp. reperire le informazioni su dove reperire le risorse (ad exp.
           per evitare di criptarle) non utilizzate i nomi delle section tipo .rsrc visto che
           questi sono _puramente_ convenzionali: nessuno ci garantisce cosa ci sia dentro o
           che qualcuno li abbia rinominati (molti crypters lo fanno). Detto questo va da se
           che i dati qui presenti devono essere ASSOLUTAMENTE coerenti o il programma si
           piantera'inesorabilmente.

Di seguito al OptionalHeader inzia l'array di strutture IMAGE_SECTION_HEADER noto come
sections table: ogni elemento di questo array descrive i dati essenziali di una sezione 
presente nel file di cui come al solito analizziamo i piu' importanti:
* SName: stringa di 8 byte con il nome della sezione (attenzione che non e' null termined)
* SVirtualSize: convenzionalmente contiene la dimensione fisica (vedi SizeOfRawData) dei dati
           arrotondata ad un multiplo del section aligment. Questo campo in pratica dovrebbe
           dire al loader quanto spazio riservare in memoria per questa sezione. Notate che
           ho usato il condizionale perche' il loader sembra perfettamente ignorare questo 
           campo in presenza di una rawsize "valida" ed effetuare da se i calcoli per una 
           VSize corretta. Questo probabilmente spiega anche il fatto che la ImageSize venga
           ignorata da w9x. Cmq e' anche perfettamente lecito avere una rawsize = 0 e una
           VSize=0x1000,tant'e' che i packer sfruttano proprio questa caratteristica 
           cambiando la rawsize ma lasciando inalterata la VSize (a dir il vero la VSize puo'
           anche sovrapporsi alla sezione successiva dato che e' cmq uno spazio solo 
           "riservato" e non necessariamente utilizzato) purche' ovviamente non ci sia vera 
           sovrascrizione :) Morale: il loader di win32 e' meno fesso del previsto, e scieglie
           con oculatezza (in pratica e' probabile faccia max(VSize,RawSize) quali informazioni 
           siano piu' coerenti o se le calcola da se. Prendete esempio :))
* SVirtualAddress: tada'ecco un altro RVA :) .. questo permette di calcolare la posizione che
           avra' la sezione una volta caricata in memoria dal loader. Come ormai avrete
           capito deve essere maggiore, o un multiplo, del section alignment (che lo ricordiano
           non puo' essere minore di 0x1000 per compatibilita' con 9x)
* SizeOfRawData: la dimensione fisicamente occupata dai dati su disco solitamente allineata
           al file alignment. Questo campo puo' essere totalmente indipendente dalla VSize
           ad exp. spesso incontrerete sezioni con rawsize = 0 ma che occupano spazio in
           memoria (tipicamente sezioni con dati non inizializzati (BSS, TLS, ecc.), ma cmq
           e'importante capire che almeno uno dei due valori dovra' contenere l'informazione
           dello spazio da minimo da riservare in memoria. Tenete conto di questa anomalia
           quando calcolate la ImageSize.
* PointerToRawData: l'offset "fisico" a cui troverete i dati della sezione
* SFlags: i flag che identificano le caratterestiche (codice,dati,ecc.) e quindi le i flags
           e le protezioni di pagina che verranno applicate (writable,readable,ecc.)

Bene abbiamo analizzato gli headers che precedono i dati veri e propri delle sezioni..
resta solo da notare che in effetti tra la fine dell'ultimo section header e l'inizio dei
dati spesso si trova una "cavita'" ovvero un blocco non utilizzato ma presente per questioni
di allineamento. Queste cavita' presenti anche tra le sezioni possono essere sfruttate per
salvare codice e/o dati a patto che siano abbastanza grandi (i virus sono un classico esempio
di utilizzatori di queste cavita'). Fra tutte queste cavita' quella che piu' ci interessa 
(miii che squallidi doppi sensi ;)) e' proprio quella fra la sections table e l'inizio 
della prima sezione, in quanto e' li che possiamo introdurre una nuova sezione 
seplicemente incrementando il campo FileHeader. NumberOfSection e accodando una struttura 
IMAGE_SECTION_HEADER all'array.. ovviamente questo discorso e' valido se c'e' abbastanza 
spazio (attenzione che per spazio va inteso quella tra la fine degli NTHeaders e l'RVA della 
prima sezione e non solo lo spazio "fisico", che normalmente e' minore per via che di solito
file alignment < section alignment) alrimenti dobbiamo "necessariamente" appendere il nostro 
codice/dati nell'ultima sezione del file (oddio non e'proprio necessario che sia l'ultima, 
potremmo sciegliere una sezione qualsiasi, ma sicuramente e' molto piu' semplice che alterare 
gli RVA di tutte quelle sucessive).

Ok, ora dovremmo trattare le strutture collegate alla IT,(la ET la trattero' nella terzo
tutorial), rilocazione e alle risorse ma credo che sia meglio che le vediate all'opera quando 
commentero' il codice del crypter. Prima di tuffarci nel codice sara' pero' il caso che 
parliamo dei concetti di ImageBase e RVA che come avrete constatato permeano tutta la 
struttura del PE.

#ImageBase e Relative Virtual Address#
L'image base e' sostanzialmente l'indirizzo lineare a cui il loader mappera' l'immagine
dell'eseguibile quando crea un nuovo processo, o carica un modulo (DLL). Questo indirizzo,
riportato nel campo OptionalHeader.ImageBase, e' _specifico_ per ogni eseguibile ed e'
essenzialmente l'indirizzo utilizzato (o specificato da noi) dal linker per risolvere i
fixup. Tuttavia non sempre il loader puo' caricare l'immagine alla ImageBase specificata 
(detta appunto "preferred"): questa eventualita' (chiamata "collisione"), e' sostanzialmente 
impossibile per gli eseguibili (ovviamente se consideriamo il fatto che ogni processo win32 
ha un suo spazio di indirizzamento "assolutamnete" privato.. per gli exe vedrete infatti 
sempre specificata come imagebase 0x400000) ma e' altamente probabile per una DLL che invece 
puo' essere caricata nello arena condivisa ( > 2gb e < 3gb in 9x; Nt non ha spazi r3 shared)
o cmq in un'area gia' impegnata da una precedente allocazione di memoria. Se si verifica una
collisione il loader per permettere all'esegubile di funzioanare sara' costretto ad applicare
la c.d. base relocation, a patchare cioe' tutti qui riferimenti assoluti che il programma 
utilizza in modo che siano di nuovo coerenti. Considerati questi problemi si e' pensato di 
"virtualizzare" gli indirizzi assoluti almeno delle strutture utilizzate dal loader rendendo
cosi' possibile referenziare le informazioni salvate dal linker a prescindere dalla imagebase:
ecco quindi nascere l'idea dell'RVA, che e' appunto un scostamento relativo alla imagebase: 
quindi se volete leggere il valore di una DWORD che sta ad un RVA = 1234 basta che gli 
sommiate l'imagebase ed otterrete il suo Virtual Address (VA) cioe' l'indirizzo nello spazio 
di indirizzamento del processo: 
VA       = RVA    + ImageBase
0x401234 = 0x1234 + 0x400000
Ovviamente questo ragionamento e' valido se l'eseguibile e' stato mappato dal loader, perche'
come sappiamo questo terra' conto del section alignment... ma se volessimo ottenere un offset
"fisico" (su disco,MMF) dato un VA ?
in questo caso dovremmo utilizzare le informazioni relative alla sezione che contiene
quell'indirizzo (ovviamente dobbiamo trovarla cercando nella section table verificando che
SVirtualAddress <= VA <= SVirtualAddress + SVirtualSize), relativizzare l'indirizzo rispetto
all'inizio di quella sezione sottraendo l'imagebase e VA della sezione, ottenendo cosi' un
offset che andremo a sommare all'offset fisico della sezione stessa:
RAW OFS = (VA       - ImageBase - SVirtualAddress) + PointerToRawData
0x834   = (0x401234 - 0x400000  - 0x1000         ) + 0x600

Bene queto e' tutto per i concetti di base: ora passiamo al codice vero e proprio.


--==[ UN ESEMPIO PRATICO ]==-------------------------------------------------------------------

I sorgenti che vi presento sono un esempio di semplice scheletro di crypter che supporta sia
l'append che l'inserimento di una nuova sezione. Il crypter e' capace di gestire  sia
sezioni codice, dati (esclusa .rdata), relocations info,import table, e risorse.
Quello che ancora non fa e' gestire tutta la casistica presente nei formati PE diciamo
"non convenzionali" (come al solito mamma M$ in testa!) , e cioe' forwarding , pre-binding
old-style e new-style, deferred dll, o la gestione del TLS. Altra mancanza di rilievo
(voluta visto che l'ho fatto in poko tempo e che sono sorgenti didattici.. ehhe non posso
mika svelarvi tutto del crypter che sto facendo :)) e l'assenza di forme di anti-dump,
anti-debug o anti-disasm. Ad ogni buon conto e' sufficientemente completo per iniziare a 
capire il funzionamento del PE. Ovviamente non vi riporto qui tutti i sorgenti (fate 
riferimento a pesentry.asm) ma solo alcuni passaggi diciamo piu' cruciali ed alcune scelte
d'implementazione.

open_file:
        mov     [lpszFileName],edi

        call    OpenFileEx                      ; open file with attribes ovveride
        cmp     eax, INVALID_HANDLE_VALUE       
        jz      @@file_error
      
prima considerazione : la funzione OpenFileEx apre il file assicurandosi pero' di salvare
gli attributi del file nonche' data,ora di creazione,ecc.. mi sempra un modo + pulito di
operare :)

        add     eax,loader_len+(2000h)     ; loader size + typical file align * 2
      
        call    CreateFileMapping,[hFile],NULL,PAGE_READWRITE,0,eax,NULL
        or      eax,eax
        jz      @@unable_to_map
      
        mov     [hFileMap],eax
              
	call    MapViewOfFile,eax,FILE_MAP_WRITE,0,0,0    ; map entire file
	or      eax,eax
        jz      @@unable_to_map
	
	mov     [Image_Base],eax
	mov     edi,eax

come vedete ho scelto di utilizzare i MMF per manipolare l'eseguibile, la ragione e' che in
questo modo posso gestire gli offset direttamente come scostamenti in memoria essendo sicuro
di avere il file mappato in modo lineare. Questo metodo di procedere e' in sostanza lo stesso
che utilizza il loader.. va notato pero' che i MMF hanno una loro piccola pecca, non possono
essere ridimensionati una volta creati.. cio' ci costringe a prevedere un blocco abbastanza
grande da contenere anche il nostro loader: sara' sufficente che sommiamo alla dimensione del
file la size del codice/dati nostro loader + 2 pagine. Se prevedete di realizzare un packer o
cmq di manipolare pesantemente il PE  , vi consiglio (vero xOA ? :) di usare buffers allocati
con VirtualAlloc che sono modificabili senza denneggiare i dati gia' caricati (VirtualReAlloc).
Il puntatore ottenuto dalla MapViewOfFile costituisce ora la nostra ImageBase.
Una piccola nota: come vedete i commenti nei sorgenti sono in inglese.. ehhe ragazzi
sorry ma sono abituato cosi'.. l'inglese e' piu' conciso per certe cose :)
	
        call    GetNtHeader
        or      eax,eax                                    ; on exit EDI = lpPEHeader
        jnz     @@invalid_pe
      
        mov     [lpPEHeader],edi

questa call esegue un check per verificare che effetivamente abbiamo a che fare con
un file pe eseguibile e nel caso affermativo torna il ptr al NTHeaders:

GetNtHeader:
        push    ebp
        mov     ebp,esp
        push    ebp                                      ; save safe ESP
        push    offset @@on_PE_except                    ; our simple handler
        push	dword ptr fs:[0]                         ; save previous frame
        mov	fs:[0],esp	                         ; establish our SEH frame
        cmp     word ptr [edi],IMAGE_DOS_SIGNATURE       ; check MZ signature
        jnz     short @@not_PE
        mov     eax,[edi.e_lfanew]
        add     edi,eax
        cmp     dword ptr [edi],IMAGE_NT_SIGNATURE       ; check PE signature
        jb      short @@not_PE                                
        mov     eax,dword ptr [edi.FileHeader.ImgFlags]
        not     al
        or      al,IMAGE_FILE_EXECUTABLE_IMAGE           ; check for executable flag
        jz      short @@is_PE
        or      ax,IMAGE_FILE_DLL
        jz      short @@not_PE
      
@@is_PE:xor     eax,eax
        jmp     short @@valid_pe
@@on_PE_except:
        mov     eax,[esp+8]                              ; get ERR structure
        mov     ebp,[eax+8]                              ; ERR + 8 = safe ESP
@@not_PE:
        stc
        sbb     eax,eax
@@valid_pe:
        pop     dword ptr fs:[0]                         ; remove SEH frame
        mov     esp,ebp     
        pop     ebp
      ret

come vedete verifico le due signature e la presenza dei flag caratteristici degli
eseguibili.. l'unica cosa degna di nota oltre a questo e' la presenza di un exception 
frame.. un modo decisamente piu' rapito che una serie di call a IsBadxxxxxPtr,ecc. per 
verificare i puntatori. da qui in poi EDI sara' il puntatore agli NTHeaders

        movzx   eax, [edi.FileHeader.SizeOfOptionalHeader] ; size of optional header
        lea     eax,[edi+eax+18h]
        mov     [lpSectionTable],eax

qui otteniamo il puntatore all'inizio della Section table, che ci servira' per leggere
le info di ogni section e per aggiungere il nostro loader creando una sezione nuova
o espandendo l'ultima
      
        mov     eax,[edi.OptionalHeader.ImageBase]
;        mov     eax,400000h
        mov     [preferred_base],eax
        mov     eax,[edi.OptionalHeader.DataDirectory.(IMAGE_DIR_IMPORT).VirtualAddress]
        mov     [it_rva],eax
        mov     eax,[edi.OptionalHeader.DataDirectory.(IMAGE_DIR_EXPORT).VirtualAddress]
        mov     [et_rva],eax
        mov     eax,[edi.OptionalHeader.DataDirectory.(IMAGE_DIR_RELOC).VirtualAddress]
        mov     [reloc_rva],eax
        mov     eax,[edi.OptionalHeader.DataDirectory.(IMAGE_DIR_TLS).VirtualAddress]
        mov     [tls_rva],eax
        mov     eax,[edi.OptionalHeader.DataDirectory.(IMAGE_DIR_RESOURCE).VirtualAddress]
        mov     [rsrc_rva],eax

qui salviamo in variabili statiche allocate nel loader gli RVA delle principali directories
che poi ci serviranno sia per modificare gli RVA in modo che puntino alle nostre stutture sia
al loader per riaggiuistare le cose a runtime. (nota il mov 0x400000 e' li' nel caso vogliate 
sperimentare con la rilocazione.. in questo caso dovrete cambiare l'imagebase del file da 
procdump in modo da forzare il load ad un altro linear address.
Fatto questo si passa a cryptare le varie sezioni:

encrypt_objects:
        movzx   edx,[edi.FileHeader.NumberOfSections] ; number of section as counter
        xor     ebx,ebx

@@next_obj:
        call    IsEncryptableObj                      ; check if section is encryptable
        or      eax,eax
        jz      short @@proceed                     
        mov    dword ptr [crypt_flag],20202020h       ; display status = skipped
        jmp    short @@no_encrypt

come counter per il loop utilizziamo il numero di sezioni riportate nell'optional header:
questo potrebbe essere una potenziale fonte di problemi visto che come ho detto il loader
non si fila molto questo valore. per cui in un file potrebbe essere maliziosamente
(si' perche' non vedo quale cacchio di linker si metterebbe a giocare con questo campo!??)
incoerente. So far so good.. continuiamo..
la call IsEncryptableObj verifica che la sezione che stiamo per elaborare sia effetivamente
criptabile: ad exp. la sezione .rdata e' una una di quelle che ci conviene evitare visto che 
e' spesso utilizzata da M$ (mortacci a loro!) per inserirci  la export, la TLS,ecc. altra 
sezione da cui star lontano e' .edata che dovrebbe contenere esplicitamente la export table..
come criterio di verifica ho adottato un check "euristico" basato sugli rva presenti nella 
DataDirectory, sulle rawsize delle sezioni, tranne che per .rdata che e' verificata in base 
al nome :(
Ora qui si pone un interessante problema: ma se ad exp. la export table fosse contenuta
nella sezione .text (altra porkeria assolutamente possibile ma abbastanza remota per fortuna)
il crypter skipperebbe tutta la sezione.. risposta positiva !.. per ovviare al problema 
bisogna identificare dove risiedono i blocchi non cryptabili in termini di RVA e quindi 
costruirsi una mappa di quello che si deve effettivamente cryptare (puo' bastare un array 
RVA + SIZE) che poi verra' usata sia dalla routine di encryption che dal loader. Ovviamente 
in questo sorgente non e' implementato questo meccanismo (te pareva ;)) perche' avrebbe 
complicato il codice che e' gia lungo di per se'..

@@proceed:
        mov     eax,[esi.SVirtualAddress]
        mov     [section_array.section_rva+ebx*8], eax      ; save rva to loader table
        mov     ecx,[esi.SizeOfRawData]
        mov     [section_array.section_vsize+ebx*8], ecx    ; save raw size

ok.. se siamo qui vuol dire che la sezione e' criptabile.. salviamo gli RVA e le dimensioni
delle sezioni cryptate in una tabella in modo che il loader sappia cosa abbiamo criptato...
quindi usiamo SizeOfRawData come grandezza del blocco da crittare

        pusha                                               ; save lpPEHeader
        mov     edi,[esi.PointerToRawData]                  ; calc pointer to raw data
        add     edi,[Image_Base]
        cmp     eax,[rsrc_rva]
        jz      short @@handle_res
        call    Encrypt
        jmp     short @@dummy_e
@@handle_res: 
        mov     eax,offset ResEncryptCallBack   
        call    EnumResources
@@dummy_e:      
        popa

        inc     ebx                                ; update loader table index
        inc     byte ptr [sections_num]            ; update loader section counter
        mov     dword ptr [crypt_flag],53455920h   ; display status = processed

ok.. questo codice mi pare autoesplicativo.. innanzitutto calcola il ptr ai dati in memoria
quindi verifica che quella che stiamo elaborando non sia la sezione delle risorse.. in caso
affermativo switcha alla routine di attraversamento dell'albero delle risorse (la spieghero'
piu' avanti..) quindi incrementa il contatore delle sezioni effetivamente criptate che poi 
il loader usera'a runtime..

@@no_encrypt:
        call    show_stats                         ; display some stats
        or      [esi.SFlags],IMAGE_SCN_MEM_WRITE   ; enable write bit always
        add     esi,IMAGE_SECTION_HEADER_          ; next section in table
        dec     edx
        jnz     short @@next_obj
       ret

questa parte invece merita qualche commento perche' immagino qualcuno si stia domandando
perche' setto il flag writable per tutte le sezioni e non solo per quelle criptate..
la ragione e' semplice: la base rilocation! gia'.. sicomme saremo noi a gestirla al posto 
del loader dobbiamo assicurarci che ogni sezione sia scrivibile alrimenti a runtime dovremmo
usare WriteProcessMemory per superare le protezioni di pagina ed applicare i fixup.. 
per inciso questo e' uno dei classici indicatori per sapere se un file e' cryptato con un 
crypter che gestiste anche la .reloc

        movzx   eax,[edi.FileHeader.NumberOfSections]  ; number of sections
        inc     eax                                    ; +1
        mov     ecx,IMAGE_SECTION_HEADER_              ; * sizeOf(section_header)
        mul     ecx                                    ;
        add     eax,[lpSectionTable]                   ; offset of object table
        mov     esi,eax
        mov     edx,edi                                ; + lpPEHeader
        add     edx,[edi.OptionalHeader.SizeOfHeaders] ; + SizeOfHeaders
        cmp     eax,edx
        jg      @@append_to_last

ecco qui un'altra porkeria ;) : questo blocco verifica nel modo piu' semplice se c'e' 
abbastanza spazio tra la fine della section table e l'inizio delle raw section in caso 
positivo il crypter creara' una nuova section. Se invece non dovesse essereci spazio optera'
per l'append. Ora vediamo in breve in meccanismo di aggiunta di una section:

        sub     esi,IMAGE_SECTION_HEADER_       
        mov     [lpLoaderSection],esi7
        inc     [edi.FileHeader.NumberOfSections]      ; add our section

ok.. otteniamo in ESI un puntatore allo spazio non utilizzato che segue l'ultima section;
e quindi incrementiamo il numero di sezioni nell'header
      
        mov     eax,[(esi-IMAGE_SECTION_HEADER_).SVirtualSize]
        mov     ebx,[(esi-IMAGE_SECTION_HEADER_).SizeOfRawData]
        cmp     ebx,eax
        jle     @dummy_sz
        xchg    eax,ebx
@dummy_sz:      
        add     eax,[(esi-IMAGE_SECTION_HEADER_).SVirtualAddress]
        call    SectionAlign
        mov     [ldr_obj_VA],eax
        mov     [loader_rva],eax

ora dobbiamo calcolare l'RVA della nostra nuova sezione in memoria, come vedete il codice 
utilizza la maggiore quantita' fra la VSize e SizeOfRawData allineata al section alignment 
e la somma al VA dell'ultima sezione; il fatto di utilizzara max(VSize,RawSize) e' quello 
che io chiamo safe programming.. come dire meglio prevenire che curare ;)

        xchg    dword ptr [edi.OptionalHeader.AddressOfEntryPoint],eax
        mov     [original_erva],eax

calcolato l'RVA della nostra sezione abbiamo anche l'RVA del nuovo entrypoint, dato che si
presuppone che l'inizio del vostro codice coincida con l'inizio dei dati nella nuova sezione 
(in caso contrario dovrete solo sommarci lo scostamento), quindi lo scriviamo nell'header 
assicurandoci pero' di salvare il vecchio entrypoint che servira' poi al loader per restituire
il controllo al programma una volta decrittato

        mov     eax,loader_len
        call    SectionAlign
        mov     [ldr_obj_VS],eax
        mov     eax,loader_len
        call    FileAlign
        mov     [ldr_obj_RWS],eax

quindi calcoliamo la nuova VSize e RawSize
      
        mov     ebx,[(esi-IMAGE_SECTION_HEADER_).PointerToRawData]
        mov     eax,[(esi-IMAGE_SECTION_HEADER_).SizeOfRawData]
        add     ebx,eax
        xor     edx,edx
        mov     ecx,[edi.OptionalHeader.FileAlignment]
        div     ecx
        or      edx,edx                         ; previus section already file aligned ?
        mov     eax,ebx
        jz      short @@no_zpad                 
        add     ebx,[Image_Base]                ; no cave
        xor     cl,cl
@@zpad:      
        mov     byte ptr [ebx],cl
        inc     ebx
        dec     edx
        jnz     @@zpad
@@no_zpad:      
        call    FileAlign
        mov     [ldr_obj_RWA], eax              ; file align loader section

questo snippet non fa altro che calcolare l'offset in cui dobbiamo scrivere i nostri dati
ovvero dalla fine dei dati precedenti accertandosi pero' che quest'ultimo offset sia
allineato
al file alignment e proveddendo allo zeropad nel caso non lo fosse..

        mov     eax,[ldr_obj_VS]
        add     eax,[edi.OptionalHeader.SizeOfImage]
        call    SectionAlign
        mov     [edi.OptionalHeader.SizeOfImage],eax

ora aggiustiamo l'imagesize aggiungendo la vsize della nostra sezione, cosi' NT non si
inkazzera' con noi

        call    RedirectReloc                    ; redirect reloc table to our
        call    RedirectIT                       ; redirect IT to loader built-in one

eheh questo invece e' un simpatico giochetto che va spiegato:
con queste due call sostituiamo nella data directory gli RVA della import table e della
reloc table in modo che puntino a quelle hardcoded che abbiamo approntato nel codice
del nostro loader. Questa operazione ha diversi vantaggi:
1) siccome la nostra reloc table e' vuota diciamo al loader di winsoz di non applicare
   alcuna relocation in caso ci sia una collisione altrimenti sarebbe una catastrofe
   in fase di decrittazione
2) impostando la nuova import table, facciamo in modo che sia windows stesso a patcharci
   la nostra IAT e a fornirci gli address delle API di cui necessitiamo evitandoci di
   ricorre a metodi piu' o meno euristici (usati in molti virii) come quello di trovare
   il base address di kernel32 (che come noto puo' cambiare con ogni nuova versione ed
   e' differente in 9x e Nt) quindi scannare la export table manualmente per ricavare
   gli address degli entrypoint di GetProcAddress, LoadLibraryA/W, GetModuleHandleA.
3) in questo modo abbiamo anche alterato l'NT Header e questo ci garantisce che un
   eventuale cracker che si accinga ad unpakkare la nostra creatura dovra' anche
   ripristinare correttamente gli RVA nella data entry se vorra' che il programma funzioni
Siccome so che siete attenti,avrete notato che non ho ridiretto l'RVA della sezione
risorse: eheh in effeti questo e' abbastanza semplice come sistema, e' sufficente
harcodare una resource directory nel nostro loader con lo stesso metodo che abbiamo usato
per la IT. In questo modo potremmo ad esempio avere la possibilita' di visualizzare
delle dialog, dei bmp, o al limite sostituire l'icona del programma con la nostra.
Per far in modo poi che il programma "ritrovi" le sue risorse sara' sufficiente che
reimpostiamo l'RVA originale nell'header (attenzione che dovrete usare WriteProtectMemory
per patchare runtime se non volete un bel gpf). Ma allora perche'non ho messo il codice
per questa features.. semplice.. lo spieghero' nel terzo tutorial quando affronteremo le
tecniche antidump.. per ora accontentatevi!.. ho gia' scritto un mezzo romanzo! ;)))
     
        mov     edi,offset loader_obj
        xchg    edi,esi
        mov     ecx, IMAGE_SECTION_HEADER_
        rep     movsb
        mov     edi,[ldr_obj_RWA]                ; edi = offset to loader section
        mov     ebx,[Image_Base]
        add     edi,ebx
        jmp    @@write_loader

bene ora abbiamo impostato corretamente i dati della sezione non ci resta che copiarla
in coda all'array della sections table, et voila'..
quello che segue invece e' codice per appendere il nostro loader nell'ultima sezione.
In genere questo metodo e' da preferirsi a quello precedente della nuova sezione, perche' 
vi permette di "cammuffare" il fatto che il programma sia criptato, dato che con un 
hexeditor o un pe-browser tutto sembrera' normale ad occhi non esperti.
Per ragioni di spazio (e crampi alle dita ;)) saro' succinto nei commenti anche perche'
non c'e' molto da dire se avete letto con attenzione la parte precente:

        mov     ebx,[esi.SVirtualAddress]
        mov     eax,[esi.SizeOfRawData]
        lea     ebx,[eax+ebx+4]                  ; calculate new entrypoint rva
        mov     [loader_rva],ebx
        xchg    dword ptr [edi.OptionalHeader.AddressOfEntryPoint],ebx
        mov     [original_erva],ebx
      
l'RVA del nuovo entrypoint e' sostanzialmente uguale a (RVA sezione precedente +
RawSize sezione precedente + 4) dove il +4 si spiega con il fatto che ci garantiamo che
ci sia una DWORD nulla tra noi e la fine dei dati originali, questo perche' con ogni
probabilita' quella che modificheremo sara' la .reloc e quindi dobbiamo mantenere
un spazio vuoto che funga da terminatore per i dati per la relocation

        add     eax,loader_len     
        call    SectionAlign
        mov     [esi.SVirtualSize],eax    
        add     eax,[esi.SVirtualAddress]        ; imagesize = last_obj.VA + last_obj.VS
        mov     [edi.OptionalHeader.SizeOfImage],eax

classico direi: aggiunstiamo la imagesize come somma dell'RVA dell'ultima sezione
e la nuova VSize ottenuta dall'allineamento della RawSize al section alignment

        mov     eax,[esi.SFlags]
        and     eax,IMAGE_SCN_MEM_NOT_DISCARDABLE
        or      eax,IMAGE_SCN_MEM_EXECUTE + \
                    IMAGE_SCN_MEM_READ    + \
                    IMAGE_SCN_MEM_WRITE 
        mov     [esi.SFlags],eax                    

forziamo i flags writable, readable, executable per essere sicuri di non aver problemi
                           
        mov     ebp,[esi.SizeOfRawData]
        lea     eax,[ebp+loader_len+4]
        call    FileAlign
        mov     [esi.SizeOfRawData],eax

allineamo la rawsize al file alignment
      
        mov     edi,[esi.PointerToRawData]      
        add     edi,ebp
        mov     ebx,[Image_Base]
        add     edi,ebx
        xor     eax,eax                          ; calc offset to the end of rawdata
        stosd                                    ; last dword = 0 (mark end of reloc)

forziamo a zero quel pad di 4byte di cui sopra e quindi ora siamo pronti a copiare
il nostro loader..
Again, non riporto il codice che copia il nostro loader  perche' e' semplicissimo,
l'unica nota e' che ho previsto che zeropaddi l'eventuale cavita' che si crea alla
fine del file per via dell'allineamento. Finita la copia del loader il crypter usa
UnmapViewOfFile, CloseHandle per rilasciare il MMF e chiama SetFilePointer e SetEndOfFile
per troncare la dimensione del file a quella effetivamente necessaria (= ESI calcolato
prendendo l'offset finale in uscita dal blocco di copia allineato al file alignment).

That's All.

Ora invece discuteremo di alcune delle piu' importanti funzioni utilizzate dal crypter
       
RedirectIT:
        mov     eax,[loader_rva]                       ; rva of decryptor
        add     eax,it_start-ldr_start                 ; add delta
        mov     [edi.OptionalHeader.DataDirectory.(IMAGE_DIR_IMPORT).VirtualAddress],eax
        mov     [edi.OptionalHeader.DataDirectory.(IMAGE_DIR_IMPORT).Size], it_len      
        add     dword ptr k32_original,eax             ; kernel32
        add     dword ptr k32_dll,eax                  ;
        add     dword ptr k32_first,eax                ;
        xor     edx,edx
@@adj_k32iat:      
        add     [func_k32+edx*4],eax
        add     [apiGetProcAddress+edx*4],eax
        inc     edx
        cmp     edx,size_k32_iat
        jnz     short @@adj_k32iat
        add     dword ptr u32_original,eax             ; user32
        add     dword ptr u32_dll,eax                  ;
        add     dword ptr u32_first,eax                ;       
        xor     edx,edx
@@adj_u32iat:      
        add     [func_u32+edx*4],eax
        add     [apiGetProcAddress+edx*4],eax
        inc     edx
        cmp     edx,size_u32_iat
        jnz     short @@adj_u32iat
      ret

questa funzione in sostanza riaggiusta gli RVA interni alla IT in modo che siano coerenti
con la posizione (quindi ancora RVA) in cui sara' mappato il nostro codice. Per comprendere
il perche' di queste correzioni bisogna che analizziamo la struttura della IT.
La import table come sapete permette al loader di reperire le informazioni relative
alle funzioni importate da moduli esterni in modo implicito.
Per far questo esso percorre una serie di strutture nella IT che contengono il nome o 
l'ordinal (= ID che identifica univocamente la funzione e relativo alla sua posizione 
nell'array AddressOfFunctions della ET) delle funzioni importate ordinate per modulo di 
appartenenza.. quindi mappa il modulo nello spazio di indirizzamento del processo 
(LoadLibrary),scanna l'ET del modulo (GetProcAddress) per trovare l'address dell'entrypoint
della funzione e quindi patcha la IAT con quest'ultimo.
Ora mi aspetto una vostra  domanda del tipo: "ma cos'e' la IAT" ?
Immaginate la Import Address Table come un array di DWORD che contiene gli indirizzi delle 
funzioni delle DLL che il programma utilizza. L'esistenza della IAT e' dovuta al fatto che 
sia il compilatore, sia il linker non possono conoscere a priopri l'address a cui verra' 
caricata la dll e quindi per consetire al programmatore di utilizzare nel suo codice ad exp. 
MessageBoxA devono approntare un meccanismo di indirezione: una chiamata da un linguaggio
ad alto livello a MessageBoxA verra' tradotta dal compilatore e dal linkere (attraverso
una import lib) in una call ad un thunk (normalmente in fondo alla sezione con il codice 
.text,CODE",ecc).class" tppabs="http://www.crackstore.com/tutorz/,ecc).class" che si prensenta cosi':

JMP DWORD PTR [0x12345678] 

dove 0x12345678 e' proprio l'indirizzo della DWORD presente nella IAT che a runtime conterra'
l'entrypoint di MessageBoxA. Alternativamente nei compilatori piu' recenti e' possibile usare
il modificatore __declspec(dllimport) per specificare che il simbolo esterno e' proprio una
funzione esportata da una dll: questo permette al compilatore di eliminare il thunk e di
tradurre la chiamata in una piu' performante 

CALL DWORD PTR [0x12345678]

Come vedete la IAT e' di vitale importanza e come logicamente si puo' intuire non facilmente
ridirezionabile tant'e' che sebbene noi modificiamo l'header in modo che punti alla nostra
IAT, l'RVA in cui andremo a patchare gli indirizzi restera' quello originale (quest'ultimo
punto e' di vitale importanza per comprendere come sia possibile per un cracker intercettare
la IAT originale). Torniamo alla IT:
questa inizia con un array di strutture IMAGE_IMPORT_DESCRIPTOR:

* OriginalFirstThunk: e' un RVA ad un array di strutture IMAGE_THUNK_DATA che contengono
     le informazioni per ogni funzione importata da questo modulo. La fine dell'array
     e' segnalato da un elemento IMAGE_THUNK_DATA nullo. Questo array a differenza di quello
     a cui punta FirstThunk non e' patchato dal Loader di Win32. Tuttavia la sua presenza 
     non e' garantita dato che alcuni linker per ottimizzire (vedi borland) lo omettono per 
     cui accertatevi sempre che questo RVA sia diverso da zero.
* TimeDateStamp: questo campo ha una duplice funzione a seconda che siano presenti o meno 
     funzioni bound (= gli address delle funzioni sono assoluti e gia'patchati dal linker 
     o dall'utility bind (fornita con l'SDK NT) che assume una determinata imagebase per 
     quel modulo):
      - nel caso di funzioni bound avra' valore diverso da zero: se vale 0xFFFFFFFF siamo 
        in presenza di un pre-binding new-style, se invece e' diverso da 0xFFFFFFFF si tratta 
        di pre-binding old-style 
      - se invece vale 0 come nella stragrande maggioranza dei casi non ci sono import bound 
        e non serve a null'altro
* ForwarderChain: altro campo mistico =P indica l'indice nell'array FirstThunk del primo 
     elemento della forwarders chain, ovvero della lista di funzioni che sono importate da un
     modulo in cui a loro volta sono forwarded. Si come avete intuito e' un bel casino :) cmq
     non abbiate a preoccuparvi.. sia le funzioni bound che quelle farwarded sono merce 
     estremamente rara e dubito che ne incontrerete mai salvo decidiate di cryptare moduli di 
     sistema... pessima idea cmq ;)
* Name: questo RVA punta ad una stringa null-terminated con il nume del modulo
* FirstThunk: questo array e' simile a quello in OriginalFirstThunk con l'unica differenza
     che ne e' garantita _sempre_ l'esistenza dato che gli elementi IMAGE_THUNK_DATA qui
     contenuti verranno patchati dal loader di windoz con gli address delle funzioni...
     come avete capito questo array e' tristemente =) noto come IAT

nella IT avremo quindi in successione un elemento IMAGE_IMPORT_DESCRIPTOR per ogni modulo
da cui importiamo una o piu' funzioni; l'array e' terminato come al solito con il classico
elemento nullo. Quanto alle import bound e forwarded non mi addentro oltre in questo argomento
perche' non credo che ne troverete esempi "reali" in quanto entrambi sono meccanismi utilizzati
principalmente per dll di windowz stesso e soprattuto sotto NT. Nel caso vogliate approfondire
vi consiglio l'ottimo documento di B. Luevelsmeyer. Molto piu' importante invece parlare degli
array OriginalFirstThunk e FirstThunk. Come anticipato entrambi puntano ad due array paralleli
di IMAGE_THUNK_DATA: ogni IMAGE_THUNK_DATA e' costituito da una sola DWORD che rappresenta una
RVA ad un elemento IMAGE_IMPORT_BY_NAME. Ogni IMAGE_IMPORT_BY_NAME e' invece cosi' dichiarato:

Hint WORD
Name BYTE DUP (?)

Hint rapresenta l'ordinal della funzione ma e' coerente solo se l'elemento IMAGE_THUNK_DATA
che lo punta ha il bit piu alto accesso (usate la mask IMAGE_IMPORT_BY_ORDINAL).
Name invece e' una stringa null-terminated che riporta il nome della funzione importata.
Ecco fatto :) .. queste sono tutte le strutture coinvolte nella IT: quindi ora e' chiaro
quale sia la sequenza che il loader segue:
1) legge un IMAGE_IMPORT_DESCRIPTOR -> ricava il nome del modulo -> LoadLibrary
 2) legge un elemento IMAGE_THUNK_DATA dell'array FirstThunk (o OriginalFirstThunk se presente)
    e ricava il corrispondente elemento IMAGE_IMPORT_BY_NAME ; contemporaneamente verifica
    il bit IMAGE_IMPORT_BY_ORDINAL 
  3) dalla struct IMAGE_IMPORT_BY_NAME ricava nome/ordinal -> GetProcAddress
  4) patcha nell'array FirstThunk (IAT) l'elemento IMAGE_THUNK_DATA corrente con l'address
     della funzione costruendo cosi' la IAT
 5) ripete la 2) per ogni IMAGE_THUNK_DATA (= funzione importata) finche' incontra un elemento
    nullo
6) ripete la 1) per ogni IMAGE_IMPORT_DESCRIPTOR (= modulo "linkato") finche' incontra un 
   elemento nullo

Se guadardate il codice del nostro loader vedrete che la funzione HandleIT non fa altro che 
eseguire queste operazioni.

RedirectReloc:
        mov     eax,[loader_rva]                       ; rva of decryptor
        add     eax,NULL_RELOC-ldr_start               ; add delta
        mov     [edi.OptionalHeader.DataDirectory.(IMAGE_DIR_RELOC).VirtualAddress],eax
        mov     [edi.OptionalHeader.DataDirectory.(IMAGE_DIR_RELOC).Size], 10
      ret      

Questa funzione e' sostanzialmente gemella della precedente solo che riaggiusta, e sostituisce
nella data directory, l'RVA della nostra relocation table che come potete constatare dai
sorgenti e' vuota (fatto naturale visto che saremo noi e non il loader di windoz a gestire le
relocations). Vediamo ora la struttura della relocation table perche' una volta che vi
sara' chiara comprenderete il funzionamento della funzione HandleReloc.
La relocations table e' un sequenza di strutture IMAGE_BASE_RELOCATION che viene utilizzata
dal loader per patchare i punti dell'eseguibile in cui si e' fatto uso di indirizzi 
assoluti relativi all'imagebse assunta a link-time e che ,nel caso di rilocazione, non 
sarebbero piu' validi: immaginate una cosa tipo MOV EAX,[046707].. come vedete carica
un valore dall'address 0x46707.. ma cosa succederebbe se l'imagebase fosse 50000 ?!
l'indirizzo 0x46707 non sarebbe piu' valido e il programma leggerebbe un valore errato
o generebbe un gpf.. e' quindi necessario che il loader calcoli il DELTA (=50000-40000=10000)
e quindi lo sommi all'operando dell'istruzione MOV in modo che tutto torni a posto.
Ogni IMAGE_BASE_RELOCATION descrive i fixup da applicare per ognuna delle pagine da 4k 
(0x1000 = x86 page per chi se ne fosse dimenticato ;) in cui viene suddivisia l'immagine 
dell'eseguibile. Come si puo' arguire la "struttura" IMAGE_BASE_RELOCATION non ha una 
dimensione fissa ma se ne puo' conoscere la dimensione attraverso il suo header:

IMAGE_BASE_RELOCATION              STRUC
  RVirtualAddress         DD      0          < header
  SizeOfBlock             DD      8          < 
  TypeOffset              DW      ?         
IMAGE_BASE_RELOCATION              ENDS   

SizeOfBlock contiene appunto la dimensione del blocco incluso l'header. Se vogliamo conoscere
quante sono le relocations per questa pagina di eseguibile dobbiamo quindi fare:

RelocNumber = ('SizeOfBlock'- sizeof(IMAGE_BASE_RELOCATION.header) idiv 2

Il campo RVirtualAddress rappresenta invece l'RVA a cui inizia la pagina in cui andranno 
applicati i fixup. Il campo TypeOffset invece e' un array di WORD, ognuna delle quali
specifica 1) nel nibble piu' alto il tipo di rilocazione 2) nei restanti 12 bit lo scostamento
che sommato all'RVA ci da la posizione in cui applicare il fixup.
Il modo in cui applicheremo i fixup e' determinato dal tipo di rilocazione. Nei sorgenti e' 
presente il codice per i 4 tipi che "dovrebbero" presentarsi in eseguibili per la piattaforma
x86 ma come vedete solo il tipo 3 IMAGE_REL_BASED_HIGHLOW e' effettivamente attivo: questo 
perche' non ho _mai_ trovato un eseguibile che presenti fixup diversi dal tipo 0 (usato solo 
come padding per  l'allineamento a DWORD) o 3 e non ho informazioni in merito all'utilizzo 
dei tipi 1,2,4. Cmq sia il modo di procedere avendo un fixup tipo IMAGE_REL_BASED_HIGHLOW
e' il seguente: dobbiamo innanzitutto sommare i 12bit dell'offset all'RVA RVirtualAddress 
e quindi sommarci l'imagebase corrente, fatto questo all'indirizzo cosi' ottenunto dovremmo
sommare _tutti_ i 32bit del DELTA. Per i restanti tipi vi rimando ai sorgenti ed alla letture.

Ok, anche con le relocations siamo a posto.. ora vediamo alla risourse directory anche perche'
e' quella che presenta la struttura piu' elaborata. Innanzitutto va detto che le risorse
sono un composte dalle seguenti strutture organizzate gerarchicamente in un albero:

IMAGE_RESOURCE_DIRECTORY
IMAGE_RESOURCE_DIRECTORY_ENTRY
IMAGE_RESOURCE_DATA_ENTRY

il nodo iniziale e' sempre una struttura
IMAGE_RESOURCE_DIRECTORY i cui campi di nostro interesse sono:
* NumberOfNamedEntries 
* NumberOfIdEntries  
che indicano rispettivamente il numero di IMAGE_RESOURCE_DIRECTORY_ENTRY che utilizzano
NOMI o ID numerici come identificativi. Per cui ad ogni IMAGE_RESOURCE_DIRECTORY segue un
numero (NumberOfNamedEntries + NumberOfNamedEntries) di IMAGE_RESOURCE_DIRECTORY_ENTRY
che ha invece questa struttura:

IMAGE_RESOURCE_DIRECTORY_ENTRY      STRUCT 
  NameID                       DD   ?
  OffsetToData                 DD   ?
IMAGE_RESOURCE_DIRECTORY_ENTRY      ENDS

Il significato di Name dipende dal bit piu' alto:
se questo vale IMAGE_RESOURCE_NAME_IS_STRING i restanti 31bit sono un offset,relativo all'inzio
delle risorse, ad una struttura IMAGE_RESOURCE_DIR_STRING_U che in definitiva contiene il nome 
(in formato UNICODE) della risorsa.. nel caso il bit non sia settato allora Name rappresenta 
un ID numerico. Quest'ultimo nel caso ci troviamo nella root, rappresenta il tipo di risorsa
che troveremo nel ramo corrispispondente (definite con le costanti RT_xxxxx in imghdr.inc).
Il campo OffsetToData e' anch'esso relativo al valore del MSB: se abbiamo che e'settata la mask
IMAGE_RESOURCE_DATA_IS_DIRECTORY allora i restanti 31 bit sono un offset, sempre relativo
all'inizio delle risorse, ad un'altra IMAGE_RESOURCE_DIRECTORY che descrive il nodo di livello
inferiore, altrimenti se il bit non e' settato i 31bit sono l'offset ad una struttura
IMAGE_RESOURCE_DATA_ENTRY di cui ci interessano:
* rdOffsetToData: questo e' un RVA al blocco che contine i dati per questa risorsa
* rdSize: la dimensione del blocco dati della risorsa                        
Come vedete le strutture assumono un significato diverso a seconda del livello a cui ci 
troviamo, ma va detto che in genere non troverete piu' di tre livelli prima di arrivare
ai dati veri e propri di una risorsa: 

                                   ROOT
                             
                      RESOURCE_DIRECTORY : NUM ENTRY 3
                                    |
             +----------------------+-----------------------+
             |                      |                       |
            
       RESOURCE_ENTRY         RESOURCE_ENTRY          RESOURCE_ENTRY
            menu                  dialog                  icon
            
             |                      |                       |            
 
   RESOURCE_DIRECTORY: 3   RESOURCE_DIRECTORY: 2  RESOURCE_DIRECTORY: 3
 
             |                      |                       |
       +-----+-----+              +-+----+           +-+----+----+
       |           |              |      |           |      |    |

RESOURCE_ENTRY RESOURCE_ENTRY
    "main"      "popup"         0x10   "maindlg"    0x100 0x110 0x120

       |
   
   DATA_ENTRY
   
Ok spero che la rappresentazione "grafica" sia chiara... ad ogni modo nei miei sorgenti ho
scento di percorre l'albero delle risorse con una funzione ricorsiva:
 
EnumResources:
        push    ebp
        mov     ebp,esp
        push    ebp                                      ; save safe ESP
        push    offset @@on_r_except                     ; our simple handler
        push    dword ptr fs:[0]                         ; save previous frame
        mov     fs:[0],esp	                         ; establish our SEH frame
        xor     ecx,ecx
        call    EnumResourceDirs,edi,edi,eax,ecx,ecx
        xor     eax,eax
        jmp   @@enum_exit
@@on_r_except:
        mov     eax,[esp+8]                              ; get ERR structure
        mov     ebp,[eax+8]                              ; ERR + 8 = safe ESP
        stc
        sbb     eax,eax
@@enum_exit:
        pop     dword ptr fs:[0]                         ; remove SEH frame
        mov     esp,ebp     
        pop     ebp
     ret

questa codice prepara l'attraversamento delle risorse impostando l'adress base delle 
risorse, il livello inziale (0) e la callback che verra' invocata ad ogni nodo (notate
che ho impostato un exception frame ..la sfiga e' sempre in agguato ;))
Ho scelto di utilizzare una callback per avere a disposizione un "engine" di attraversamento
dell'albero delle risorse che mi consentisse di compiere qualsiasi tipo di operazione sui vari
nodi (ad esempio e' possibile rilocare l'intero tree semplicemente cambiando gli RVA dei data
entry mentre lo attraversiamo) avendo a disposizione le informazioni relative al livello ed al 
tipo di nodo in cui ci troviamo. Infatti se guardate i sorgenti la callback utilizzate per 
criptare (i.e.ResCryptCallBack) le risorse e' uin grado di lasciare inalterate le risorse 
RT_ICON,RT_GROUP_ICON in modo che il programma possa mostrare la sua icona nell'explorer. 
Tutto questo avviene grazie a chiamate ricorsive fra EnumResourceDirs e EnumResourceEntry
che a loro volta chiamano la callback passandogli i dati relativi al livello in cui
ci troviamo nel ramo, il tipo di nodo, ed ogni informazione utile come la base delle risorse. 
Come al solito non riporto i sorgenti.. ma credo che la spiegazione sia chiara.

Bene, ora non resta che esaminare il loader. Come e' ovvio il nostro codice dovra' essere 
indipendente dalla imagebase altrimenti anche noi avremmo il problema della rilocazione.. 
bene la soluzione sta nell'usare il buon vecchio trucco del delta-offset usato dai tempi
immemori del dos e tanto caro a virii coderz. In questo modo non avremmo piu' riferimenti
assoluti ma solo relativi. e sara' facile calcore l'imagebase a siamo stati mappati
con questo semplice codice facendo riferimento all'RVA del nostro loader:

ldr_start:
        pushfd                                          ; save host reg state
        pushad
        call    delta                                   ; get delta offset
delta:
        pop     ebp
        sub     ebp, (delta - ldr_start)                ; ebp = delta offset
        mov     eax, ebp                                ; calculate current imagebase
        sub     eax, [(loader_rva-ldr_start)+ebp]     
        mov     [@image_base+ebp],eax                   ; store for later

a dir il vero potevamo anche usare GetModuleHandle, ma diciamo che cosi' fa piu scena ;)) 
      
        mov     edx,[(original_erva-ldr_start)+ebp]     ; original entry point rva
        add     edx,eax
        mov     [esp+28],edx                            ; save host ret address

trovata l'imagebase , possiamo anche calcolarci l'entrypoint originale a cui restituiremo
il controllo una volta finito il nostro sporco lavoro

        lea     eax,[@loader_eHandler+ebp]              ; our hanlder
        push    esp                                     ; save safe ESP
        push    ebp                                     ; save delta
        push    eax
        push	dword ptr fs:[0]  
	mov	fs:[0],esp                              ; establish a SEH frame

stabiliamo un bel exception frame per ogni eventualita' in modo che il programma
in caso di problemi mostri una MessageBox piu' gentile di quello di windoz
(notate che l'address dell'hander e' calcolato con il solito delta) 
      
        xor     edx,edx
next_object:
                                                ; read section data from decryptor table      
        mov     edi, [@image_base+ebp]                         
        mov     eax, [ebp+(@section_array.section_rva)+edx*8]   ; RVA
        add     edi, eax                                  ; imagebase+rva= VA of section
        mov     ecx, [ebp+(@section_array.section_vsize)+edx*8] ; VSize
        cmp     eax,[@rsrc_rva+ebp]
        pusha
        jz      short @@handle_res_d
        call    Decrypt
        jmp     short @@dummy_d
@@handle_res_d:      
        lea     eax,[@ResDecryptCallBack+ebp]
        xor     ecx,ecx
        call    EnumResourceDirs,edi,edi,eax,ecx,ecx
@@dummy_d:
        popa

quindi il loop che decritta i dati.. che e' perfettamente simmetrico a quello dell'encryptor.
L'algoritmo di crittazione e' decisamente semplice ma serve a dimostrare che il meccanismo
della rilocazione funziona (se avessimo usato un'encryption additiva non ci sarebbe bisogno 
di prendersi cura delle rilocazioni ( A-B = C anche (A+x)-(B+x) = C). 
Una volta decrittati i dati delle sezioni, il nostro loader si occupa di gestire una eventuale
rilocazione ( HandleReloc ), e successivamente la risoluzione delle imports con il caricamento
delle DLL nello spazio di indirizzamento del programma, e la costruzione della IAT che poi 
verra' utilizzata dallo stesso. Eseguite queste operazioni l'immagine dell'eseguibile
e' stata ricostruita in memoria e di conseguenza possiamo restituire il controllo al
codice originale attraverso il canonico jmp eax (l'utilizzo eax non e' casuale: quando il 
loader di win9x passa il controllo al programma in eax c'e' infatti proprio  l'address
dell'entrypoint, quindi per eviate problemi e' meglio mimare il comportamento di windowz)

        pop	dword ptr fs:[0]                 ; remove seh frame
        add     esp,0Ch                          ; clean stack

        popa                                     ; restore host regs
        popfd

        jmp     eax                              ; jump to original entry point

--==[ NOTE FINALI]==----------------------------------------------------------------------

Miii , quando ho iniziato questo tutorial non pensavo credevo che avrei scritto tanto: 
e' davvero' lunghetto, per cui se vi siete rotti il cz, e non l'avete finito di leggere,
avete tutta la mia solidarieta' =)
Spero di essere stato chiaro, e abbastanza dettagliato, in modo che anche chi si avvicina
per la prima volta al problema dei pe-crypters possa capirci qualcosa. Chi invece e' gia'
esperto in materia mi aguro abbia apprezzato lo sforzo di coagulare le informazioni
che si possono repire sull'argomento in tutorial che presenta anche un esempio pratico.

Ok, ora e' il tempo dei greetings (tranquilli saranno brevissimi ;). 
Innanzitutto voglio ringraziare +Fravia & +HCU tutta,Stone/UCF,Virogen/PC,Hyras,Izelion,
i membri del 29/a e Ikx per aver messo a dispozione del pubblico le loro conoscenze/sorgenti 
fondamento di molte delle mie conoscenze. Ringraziamenti anche a Matt Pietrek e Andraw Shulman,
Jeffey Rithcher..  grazie di esistere :))
I miei ringraziamenti vanno poi a tutti i memberz di ringzer0 e frequentatori di #crack-it:
along3x, furbet, metalhead,suby,t3x, kry0, e tutti gli altri.. un tnx speciale va a:  

Daemon: perche' riesce sempre a farmi sparlare di M$ e VB ;) (..salutami patrizia!)
Insanity : che pubblichera' questo tute tempestivamente! ;)
Genius : che  continua a sperare che finiremo quel benetto api-hooker a r0 ;))
+Malattia: perche' e' un po' che non ci sentiamo.. fatti vivo ammorbato! :)
Neural_Notepad_Noise ;) per essere assolutamente assurdo e per aver fatto da cavia nei test ;)
Pusillus: per il suo entusiasmo incondizionato verso ringzer0 :)
xAONON : per le brevi ma intense chiaccherate sul PE 
Yan-orel: che sta sempre ad ascoltare le mie cazzate ad ore assurde :)
War-lock: perche'..... beh lasciamo stare ahaha ;))))

byz Kill3xx